package jstm;

import haxe.macro.Expr;
import haxe.macro.Context;

using StringTools;

/*
 * testing the new macro features
 * TODO:
 * - make ORM proxy generators
 */
class MacroTest {
	
    @:macro public static function buildDimensions(c:ExprRequire<Class<Dynamic>>) : Array<Field> {
		var className = haxe.macro.Context.getLocalClass().get().name;
		var unit=switch(className) {
			case 'PixelValues': 'px';
			case 'PercentageValues': 'pc';
			case 'EmValues': 'em';
			default: throw 'not allowed';
		}
		return build([
			'width', 'height',
			'left','right','top','bottom',
			'borderWidth', 'borderLeftWidth', 'borderRightWidth', 'borderTopWidth', 'borderBottomWidth',
			'margin', 'marginLeft', 'marginRight', 'marginTop', 'marginBottom',
			'padding', 'paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom'
		], unit, c);
	}
	
    #if !macro
	@:macro
	#end 
	public static function build(names:Array<String>,unit:String,c:ExprRequire<Class<Dynamic>>) : Array<Field> {
        var pos = haxe.macro.Context.currentPos();
        var fields = haxe.macro.Context.getBuildFields();
		var t = null, tName = null;
		switch(Context.typeof(c)) {
			case TType(ref, _):
				var r=ref.get(),n=r.name.replace('#', '');
				t = TPath( { pack : r.pack, name : n, params : [], sub : null } );//TODO: params
				tName = ref.toString().replace('#', '');
			default:
				Context.error('type expected', c.pos);
		}
		for (f in names) {
			fields.push( { name : 'get_' + f, doc : null, meta : [], access : [APrivate, AInline], kind : FFun( {
				args:[],
				ret : t,
				expr : Context.parse('return untyped this.read'+unit+'("'+f+'")',pos),
				params : []
			}), pos : pos } );
			fields.push( { name : 'set_' + f, doc : null, meta : [], access : [APrivate, AInline], kind : FFun( {
				args:[{
					name : 'v',
					opt : false,
					type : t,
					value : null
				}],
				ret : t,
				expr : Context.parse('return untyped this.write'+unit+'("'+f+'",v)',pos),
				params : []
			}), pos : pos } );
			fields.push({ name : f, doc : null, meta : [], access : [APublic], kind : FProp('get_'+f,'set_'+f,t), pos : pos });
		}
        return fields;
    }
	
	@:macro public static function getTypeName(e:ExprRequire<Class<Dynamic>>):Expr {
		return {expr:stringDef(_getTypeName(e)),pos:e.pos};
	}
	
	#if macro
	
	public static function _getTypeName(e:ExprRequire<Class<Dynamic>>):String {
		return switch(Context.typeof(e)) {
			case TType(ref, _):
				ref.toString().replace('#', '');
			default:
				Context.error('type expected', e.pos);
		}
	}
	
	static function stringDef(s:String):ExprDef {
		return ExprDef.EConst(Constant.CString(s));
	}
	#end
	/*
	public static function run(e:Expr):Expr {
		trace(e);
		return e;
	}
	
	public static function useType(e:ExprRequire<Class<Dynamic>>):Expr {
		var t = _getTypeName(e);
		return Context.parse('function(fn:Class<'+t+'>->Void)jstm.Runtime.loadClass("'+t+'",fn)',e.pos);
	}
	*/
}